#include "Model.h"

mini_engine::Model *mini_engine::Model::m_Model = nullptr;
VkBuffer mini_engine::Model::vertexBuffer;
VkDeviceMemory mini_engine::Model::vertexBufferMemory;

mini_engine::Model::Model()
{
}

uint32_t mini_engine::Model::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
{
    VkPhysicalDeviceMemoryProperties memProperties;
    vkGetPhysicalDeviceMemoryProperties(PhysicalDevice::physicalDevice, &memProperties);

    for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
    {
        if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
        {
            return i;
        }
    }

    throw std::runtime_error("failed to find suitable memory type!");
}

mini_engine::Model::~Model()
{
}

mini_engine::Model::ModelDestruction::~ModelDestruction()
{
    if (m_Model != nullptr)
    {
        delete m_Model;
        m_Model = nullptr;
    }
}

mini_engine::Model *mini_engine::Model::getModel()
{
    if (m_Model == nullptr)
    {
        m_Model = new Model();
        static ModelDestruction modelDestruction;
    }
    return m_Model;
}

void mini_engine::Model::createVertexBuffer()
{
    VkBufferCreateInfo bufferInfo{};
    bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    bufferInfo.size = sizeof(vertices[0]) * vertices.size();
    bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
    bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

    if (vkCreateBuffer(LogicalDevice::logicalDevice, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS)
    {
        throw std::runtime_error("failed to create vertex buffer!");
    }

    VkMemoryRequirements memRequirements;
    vkGetBufferMemoryRequirements(LogicalDevice::logicalDevice, vertexBuffer, &memRequirements);

    VkMemoryAllocateInfo allocInfo{};
    allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    allocInfo.allocationSize = memRequirements.size;
    allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

    if (vkAllocateMemory(LogicalDevice::logicalDevice, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS)
    {
        throw std::runtime_error("failed to allocate vertex buffer memory!");
    }

    vkBindBufferMemory(LogicalDevice::logicalDevice, vertexBuffer, vertexBufferMemory, 0);

    void *data;
    vkMapMemory(LogicalDevice::logicalDevice, vertexBufferMemory, 0, bufferInfo.size, 0, &data);
    memcpy(data, vertices.data(), (size_t)bufferInfo.size);
    vkUnmapMemory(LogicalDevice::logicalDevice, vertexBufferMemory);
}
